package com.ihrm.audit.service;


import com.alibaba.fastjson.JSON;
import com.ihrm.audit.client.FeignClientService;
import com.ihrm.audit.dao.ProcInstanceDao;
import com.ihrm.audit.dao.ProcTaskInstanceDao;
import com.ihrm.audit.dao.ProcUserGroupDao;
import com.ihrm.audit.entity.ProcInstance;
import com.ihrm.audit.entity.ProcTaskInstance;
import com.ihrm.audit.entity.ProcUserGroup;
import com.ihrm.common.utils.IdWorker;
import com.ihrm.domain.system.User;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.Task;
import org.hibernate.query.internal.NativeQueryImpl;
import org.hibernate.transform.Transformers;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.criteria.*;
import java.util.*;

@Service
public class AuditService {
    
    @Autowired
    private ProcInstanceDao procInstanceDao;
    
    @Autowired
    private ProcTaskInstanceDao procTaskInstanceDao;
    
    
    @Autowired
    private FeignClientService feignClientService;
    
    @Autowired
    private IdWorker idWorker;
    
    @Autowired
    private RepositoryService repositoryService;
    
    @Autowired
    private RuntimeService runtimeService;
    
    @Autowired
    private TaskService taskService;
    
    @Autowired
    private ProcUserGroupDao procUserGroupDao;
    
    @Qualifier("ihrmEntityManager")
    @Autowired
    private EntityManager entityManager;
    
    /**
     * 查询所有的业务的申请流程
     */
    public Page getInstanceList(ProcInstance instance,int page,int size){
        /**
         * 使用Specification查询，构造Specification
         */
        Specification<ProcInstance> spec = new Specification<ProcInstance>() {
            /**
             * 构造查询条件(根据传入参数判断,构造)
             */
            @Override
            public Predicate toPredicate(Root<ProcInstance> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> list = new ArrayList<>();
            
                /**
                 * 审批类型   --processKey
                 */
                if (!StringUtils.isEmpty(instance.getProcessKey())) {
                    list.add(criteriaBuilder.equal(root.get("processKey").as(String.class), instance.getProcessKey()));
                }
            
                /**
                 * 审批状态(多个，每个状态之间用","隔开)  --processState
                 */
                if (!StringUtils.isEmpty(instance.getProcessState())) {
                    Expression<String> exp = root.<String>get("processState");
                    list.add(exp.in(instance.getProcessState().split(",")));
                }
            
                /**
                 * 当前节点的待处理人  --procCurrNodeUserId()
                 */
                if (!StringUtils.isEmpty(instance.getProcCurrNodeUserId())) {
                    list.add(criteriaBuilder.like(root.get("procCurrNodeUserId").as(String.class), "%" + instance.getProcCurrNodeUserId() + "%"));
                }
            
                /**
                 * 发起人  --userId
                 */
                if (!StringUtils.isEmpty(instance.getUserId())) {
                    list.add(criteriaBuilder.equal(root.get("userId").as(String.class), instance.getUserId()));
                }
            
                return criteriaBuilder.and(list.toArray(new Predicate[list.size()]));
            }
        };
    
        /**
         * 调用dao进行Specification查询
         */
        return procInstanceDao.findAll(spec,new PageRequest(page-1,size));
    
    }
    
    /**
     * 根据id查询申请数据响应
     */
    public ProcInstance findInstanceDetail(String id){
        return procInstanceDao.findById(id).get();
    }
    
    /**
     * 流程申请
     */
    public void startProcess(Map map,String companyId){
    
        /**
         * 构造业务数据
         */
        String userId = (String) map.get("userId");
        String processKey =(String) map.get("processKey");
        String processName =(String) map.get("processName");
        User user = feignClientService.getUserInfoByUserId(userId);
        ProcInstance instance = new ProcInstance();
        BeanUtils.copyProperties(user,instance);
        instance.setUserId(userId);
        instance.setProcessId(idWorker.nextId()+"");
        instance.setProcApplyTime(new Date());
        instance.setProcessKey(processKey);
        instance.setProcessName(processName);
        instance.setProcessState("1");
        String data = JSON.toJSONString(map);
        instance.setProcData(data);
        /**
         * 查询流程定义
         */
        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(processKey)
                .processDefinitionTenantId(companyId).latestVersion().singleResult();
        /**
         * 开启流程
         */
        Map vars=new HashMap();
        if("process_leave".equals(processKey)){
            /**
             * 请假
             */
            vars.put("days",map.get("duration"));
        }
        /**
         * 流程定义的id，业务数据id，内置参数
         */
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(definition.getId(), instance.getProcessId(), vars);
    
        /**
         * 自动执行第一个任务节点
         */
    
        /**
         * 获取等待执行的任务节点
         */
        Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
    
        /**
         * 执行
         */
        taskService.complete(task.getId());
    
        /**
         * 获取下一个节点数据，填充业务数据中当前待审批人
         */
        /**
         * 获取下一个节点
         */
        Task next = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
        if(next!=null){
            List<User> users = findCurrUsers(next, user);
            String usernames="",userIds="";
            for(User user1:users){
                usernames+=user1.getUsername()+" ";
                userIds+= user1.getId();
            }
            instance.setProcCurrNodeUserId(userIds);
            instance.setProcCurrNodeUserName(usernames);
        }
        
        procInstanceDao.save(instance);
        ProcTaskInstance pti = new ProcTaskInstance();
    
        pti.setTaskId(idWorker.nextId()+"");
        pti.setProcessId(instance.getProcessId());
        pti.setHandleTime(new Date());
        pti.setHandleType("2");
        pti.setHandleUserId(userId);
        pti.setHandleUserName(user.getUsername());
        pti.setTaskKey(task.getTaskDefinitionKey());
        pti.setTaskName(task.getName());
        pti.setHandleOpinion("发起申请");
        procTaskInstanceDao.save(pti);
        
    }
    
    private List<User> findCurrUsers(Task nextTask,User user){
        /**
         * 查询任务的节点数据(候选人组)
         */
        List<IdentityLink> list = taskService.getIdentityLinksForTask(nextTask.getId());
        List<User> users = new ArrayList<>();
        for(IdentityLink identityLink:list){
            /**
             * 候选人id
             */
            String groupId = identityLink.getGroupId();
            
            /**
             * 查询userGroup
             */
            ProcUserGroup userGroup = procUserGroupDao.findById(groupId).get();
            String param = userGroup.getParam();
            String paramValue=null;
            if("user_id".equals(param)){
                paramValue = user.getId();
            }else if("department_id".equals(param)){
                paramValue=user.getDepartmentId();
            }else if("company_id".equals(param)){
                paramValue=user.getCompanyId();
            }
            String sql = userGroup.getIsql().replaceAll("\\$\\{" + param + "\\}", paramValue);
            Query query = entityManager.createNamedQuery(sql);
            query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.aliasToBean(User.class));
            users.addAll(query.getResultList());
        }
        return users;
    }
    
    
    /**
     * 提交审核
     * ProcTaskInstance
     *      handleOpinion : 操作说明
     *      handleType    : 处理类型(2 审批通过; 3 审批不通过; 4 撤销)
     *      handleUserId  : 处理人
     *      processId     : 业务流程id
     */
    public void commit(ProcTaskInstance taskInstance,String companyId){
        /**
         * 查询业务流程对象
         */
        String processId = taskInstance.getProcessId();
        ProcInstance instance = procInstanceDao.findById(processId).get();
    
        /**
         * 设置业务流程状态
         */
        instance.setProcessState(taskInstance.getHandleType());
    
        /**
         * 根据不同的操作类型，完成不同的业务处理
         */
        /**
         * 查询出activiti中的流程实例(根据自己的业务id查询activiti中的流程实例)
         */
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(processId).singleResult();
        User user = feignClientService.getUserInfoByUserId(taskInstance.getHandleUserId());
    
        /**
         * 如果审核通过，完成当前任务
         */
        if("2".equals(taskInstance.getHandleType())){
            /**
             * 查询出当前节点，并完成当前节点任务
             */
            Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
            taskService.complete(task.getId());
    
            /**
             * 查询出下一个任务节点，如果存在下一个，流程没有结束
             */
            Task next = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
            if(next!=null){
                List<User> users = findCurrUsers(next, user);
                String usernames="",userIdS="";
                for(User user1:users){
                    usernames+=user1.getUsername()+" ";
                    userIdS+=user1.getId();
                }
                instance.setProcCurrNodeUserId(userIdS);
                instance.setProcCurrNodeUserName(usernames);
                instance.setProcessState("1");
            }else {
                /**
                 * 如果不存在下一个节点，任务结束
                 */
                instance.setProcessState("2");
            }
        }else {
            /**
             * 如果审核不通过或者撤销(删除activiti流程)
             */
            runtimeService.deleteProcessInstance(processInstance.getId(),taskInstance.getHandleOpinion());
        }
    
        /**
         * 更新业务流程对象，保存业务任务对象
         */
        procInstanceDao.save(instance);
        taskInstance.setTaskId(idWorker.nextId()+"");
        taskInstance.setHandleUserName(user.getUsername());
        taskInstance.setHandleTime(new Date());
        procTaskInstanceDao.save(taskInstance);
    
    }
    
    
    /**
     * 根据processId查询业务流程明细
     */
    public List<ProcTaskInstance> findTasksByProcess(String id){
        return procTaskInstanceDao.findByProcessId(id);
    }

}
